﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GbmpScaleCADCmd.h"
#include "GbmpUiPlatformCommandIds.h"
#include "GbmpUiPlatformCommandRegister.h"
#include "CmdStatusUtils.h"
#include "IElement.h"
#include "ISelection.h"
#include "IDocument.h"
#include "IGraphicsNodeReference.h"
#include "UiDocumentViewUtils.h"
#include "IImportCADElement.h"
#include "ActionDrawStraightElementCreator.h"
#include "IUserTransaction.h"
#include "IElementTransformationComponent.h"
#include "GbmpCADScaleDlg.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

REGISTER_GM_COMMAND(GmScaleCADCmd)

namespace
{
    IElement* GetSelectedElement(const IDocument* pDocument)
    {
        ISelection* pSelection = ISelection::Get();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pSelection != nullptr, L"ISelection::Get()为空",L"GDMPLab",L"2024-03-30");
        const std::set<OwnerPtr<IGraphicsNodeReference>, OwnerPtrContainerUtil::LessPredicate<IGraphicsNodeReference>>& selectedObjs = pSelection->GetGraphicsNodeReferences();
        if (selectedObjs.size() == 1)
        {
            if (pDocument == nullptr)
                return nullptr;
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(*selectedObjs.begin(), L"指针为空",L"GDMPLab",L"2024-03-30");
            ElementId elementId = (*selectedObjs.begin())->GetElementId();
            return pDocument->GetElement(elementId);
        }
        return nullptr;
    }
}

gcmp::GmScaleCADCmd::GmScaleCADCmd() : GbmpCommandBase(ID_CMD_GBMP_SCALE_CAD)
{

}

bool gcmp::GmScaleCADCmd::IsEnabled() const
{
    CMD_ONLY_ENABLE_IN_PROJECT_ENVIRONMENT
}

bool gcmp::GmScaleCADCmd::IsVisible() const
{
    const IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc != nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");
    IElement* pElement = GetSelectedElement(pDoc);
    if (pElement == nullptr)
        return false;

    IImportCADElement* pCadElement = quick_cast<IImportCADElement>(pElement);
    if (pCadElement == nullptr)
        return false;

    CMD_ONLY_VISIBLE_IN_PROJECT_ENVIRONMENT;
}

gcmp::OwnerPtr<gcmp::IAction> gcmp::GmScaleCADCmd::ExecuteCommand(const CommandParameters& cmdParams)
{
    const IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc != nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");
    IElement* pElement = GetSelectedElement(pDoc);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElement != nullptr, L"应选择一个CAD对象",L"GDMPLab",L"2024-03-30");

    ActionDrawStraightElementInput actionInput;
    actionInput.CommandId = GetCommandId();
    actionInput.DrawLineMode = DrawLineMode::Only_One;
    actionInput.LineFinishedCallback = actionInput.CreateOnLineFinishedCallback(&GmScaleCADCmd::OnLineFinished, this);
    actionInput.PromptMessageCallback = actionInput.CreateDefinePomptMessageCallback(&GmScaleCADCmd::OnPromptMessage, this);

    return ActionDrawStraightElementCreator::Create(actionInput);
}

gcmp::ElementId gcmp::GmScaleCADCmd::OnLineFinished(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& startPt, const gcmp::Vector3d& endPt, const gcmp::ISnap* pStartSnap, const gcmp::ISnap* pEndSnap)
{
    IDocument* pDocument = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDocument != nullptr, ElementId::InvalidID, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    double dDistance = (startPt - endPt).Length();
    if (dDistance < Constants::LENGTH_EPS)
        return ElementId::InvalidID;

    GbmpCADScaleSettingDlg dlg;
    if (QDialog::Accepted == dlg.exec())
    {
        double dRealSize = dlg.GetRealSize();
        double dScale = dRealSize / dDistance;
        Matrix4d mat;
        mat.MakeScale(startPt, dScale);

        // 设置比例
        IElement* pElement = GetSelectedElement(pDocument);
        DBG_WARN_AND_RETURN_UNLESS(pElement != nullptr, ElementId::InvalidID, L"应选择DXF/PDF导入对象",L"GDMPLab",L"2024-03-30");
        OwnerPtr<IUserTransaction> ut = IUserTransaction::Create(pDocument, GBMP_TR(L"变换CAD对象比例"));
        DBG_WARN_AND_RETURN_UNLESS(ut, ElementId::InvalidID, L"ut指针为空",L"GDMPLab",L"2024-03-30");
        {
            IElementTransformationComponent* pElementTransformationComponent = pElement->GetElementTransformationComponent();
            if (pElementTransformationComponent == nullptr)
            {
                ut->Rollback();
                return ElementId::InvalidID;
            }

            if (!pElementTransformationComponent->Transform(mat))
            {
                ut->Rollback();
                return ElementId::InvalidID;
            }
        }
        ut->Commit();
    }

    return ElementId::InvalidID;
}

const std::wstring gcmp::GmScaleCADCmd::OnPromptMessage(DrawLineStatus drawLineStatus)
{
    switch (drawLineStatus)
    {
    case DrawLineStatus::Not_Started:
        break;
    case DrawLineStatus::Getting_StartPoint:
        return L"点击左键选择一条已知长度的线段起点";
    case DrawLineStatus::Getting_EndPoint:
        return L"点击左键选择这条线段的终点";
    default:
        break;
    }
    return L"";
}
